#pragma once

#include <vector>
#include <unordered_map>

#include "../NavData.h"
#include "../Time/TimeFactory.hpp"

namespace ns_GNSSObsData
{
    using namespace ns_Data;
    using namespace ns_Time;

    struct GNSSObsHeader : NavData
    {
    public:
        using VersonType = std::string;
        using Ptr = std::shared_ptr<GNSSObsHeader>;

    public:
        VersonType verson; // 版本号

        std::string markName;
        std::string markNumber;

        std::string reciverSn;
        std::string reciverType;
        std::string reciverVerson;

        std::string ANTSn; // ANT为天线接口
        std::string ANTType;

        double approxPositon[3];

        double ANTDelta[3];

        std::unordered_map<GNSSType, std::vector<std::string>> observationList;

        int interval;

        CommonTime ObsStartTime;
        CommonTime ObsEndTime;
    };

    struct GNSSObsRecord : NavData
    {
    public:
        struct GNSSObsRecordHeader
        {
            using Ptr = std::shared_ptr<GNSSObsRecordHeader>;

            CommonTime epoch;
            double reciverClockBias;
            bool useable;
        };

        using Ptr = std::shared_ptr<GNSSObsRecord>;

    public:
        GNSSObsRecordHeader::Ptr header;
        GNSSType gnssType;
        int serial;
        double pseudoRange;
        double doppler;

    public:
        bool Encode(std::string *outJson) const override
        {
            if (outJson == nullptr)
                return false;

            Json::Value outValue;
            outValue["Type"] = "GNSSObsRecord";

            outValue["GNSSType"] = static_cast<int>(gnssType);
            outValue["Serial"] = serial;
            outValue["PseudoRange"] = pseudoRange;
            outValue["Doppler"] = doppler;
            std::string epochJson;
            header->epoch.Encode(&epochJson);
            outValue["Epoch"] = JsonUtil::StringToValue(epochJson);
            outValue["ReciverClockBias"] = header->reciverClockBias;
            outValue["Useable"] = header->useable;

            Json::FastWriter writer;
            *outJson = writer.write(outValue);

            return true;
        }

        bool Decode(const std::string &inJson) override
        {
            Json::Value inValue;
            Json::Reader reader;
            bool parsingSuccessful = reader.parse(inJson, inValue);
            if (!(parsingSuccessful && inValue["Type"] == "GNSSObsRecord"))
            {
                return false;
            }

            gnssType = static_cast<GNSSType>(inValue["GNSSType"].asInt());
            serial = inValue["Serial"].asInt();
            pseudoRange = inValue["PseudoRange"].asDouble();
            doppler = inValue["Doppler"].asDouble();
            std::string epochJson = JsonUtil::ValueToString(inValue["Epoch"]);
            header = std::make_shared<GNSSObsRecordHeader>();
            if (!header->epoch.Decode(epochJson))
                return false;
            header->reciverClockBias = inValue["ReceiverClockBias"].asDouble();
            header->useable = inValue["Useable"].asBool();

            return true;
        }
    };

    class GNSSObsData
    {
    public:
        using Ptr = std::shared_ptr<GNSSObsData>;
    public:
        GNSSObsHeader::Ptr GetHeader()
        {
            return _header;
        }

        GNSSObsRecord::Ptr GetRecord()
        {
            return _record;
        }

    private:
        GNSSObsHeader::Ptr _header;
        GNSSObsRecord::Ptr _record;
    };
}
